#pragma once
#include "Sock.hpp"
#include "Err.hpp"
#include "Log.hpp"
#include <iostream>
#include <string>
#include <functional>
#include <cstring>
#include <cstdlib>
#include <sys/poll.h>


const static int N = 4096; //poll的第二个参数说明可以管理N个，管理量没有上限
const static uint16_t defaultport = 8888;
const static nfds_t defaultevent=0;


typedef struct pollfd FdEvent;
class PollServer
{
public:
    PollServer(int port = defaultport)
        : port_(defaultport)
    {
    }
    void InitServer()
    {
        listensockfd_.Socket();
        listensockfd_.Bind(port_);
        listensockfd_.Listen();

        for (int i = 0; i < N; ++i)
        {
            fd_arry[i].fd = defaultfd;
            fd_arry[i].events=defaultevent;
            fd_arry[i].revents=defaultevent;
        }

        fd_arry[0].fd=listensockfd_.Fd();
        fd_arry[0].events=POLLIN;
    }
    void Start()
    {
        // 1. 这里我们能够直接获取新的链接吗？
        // 2. 最开始的时候，我们的服务器是没有太多的sock的，甚至只有一个sock！listensock
        // 3. 在网络中， 新连接到来被当做 读事件就绪！
        // listensock_.Accept(); 不能！

        while (true)
        {
            // 1.设置我们需要关心的文件描述符，用户告诉内核
            // 2. 调用poll接口
            int n=poll(fd_arry,N,1000);
            if (n > 0)
            {
                // 有事件就绪了，开始处理
                logMessage(Info, "有事件就绪了，开始处理相关事件");
                HandlerEvent();
            }
            else if (n == 0)
            {
                logMessage(Info, "poll timeout ...,strerror:%s",strerror(errno));
            }
            else
            {
                logMessage(Warning, "poll error:%s [code:%d]", strerror(errno), errno);
            }
        }
    }
    void HandlerEvent()
    {
        for (int i = 0; i < N; ++i)
        {
            int fd = fd_arry[i].fd;
            short event=fd_arry[i].revents;
            if (fd == defaultfd)
                continue;
            if ((event&POLLIN) && (fd == listensockfd_.Fd())) // listen套接字有读事件发生了
            {
                Accepter();
            }
            if ((event&POLLIN) && (fd != listensockfd_.Fd())) // 其它的套接字有读事件发生了
            {
                ServerIO(i);
            }
        }
    }
    void Accepter()
    {
        // 1.接受客户
        std::string clientip;
        uint16_t clientport;
        int sockfd = listensockfd_.Accept(&clientip, &clientport);
        if (sockfd < 0)
            return;
        // 2. 存储sockfd到fd_array数组中
        int index = 0;
        while (index < N)
        {
            if (fd_arry[index].fd == defaultfd)
                break;
            ++index;
        }
        if (index < N)
        {
            fd_arry[index].fd = sockfd;
            fd_arry[index].events =POLLIN;
                logMessage(Info, "存储%d套接字成功！", sockfd);
        }
        else
        {
            close(sockfd);
            logMessage(Warning, "存储%d失败,fd_arry[] is full", sockfd);
        }
    }
    void ServerIO(int i)
    {
        int fd = fd_arry[i].fd;
        char buffer[1024];
        int n = recv(fd, buffer, sizeof(buffer) - 1, 0);
        if (n > 0)
        {
            buffer[n] = 0;
            std::cout << "clinet # " << buffer << std::endl;

            std::string echo = buffer;
            echo += "[server echo client]";
            send(fd, echo.c_str(), echo.size(), 0); // TODO
        }
        else
        {
            logMessage(Info, "clinet:%d quit...", fd);
            close(fd);
            fd_arry[i].fd = defaultfd;
            fd_arry[i].events=0;
            fd_arry[i].revents=0;
        }
    }

    void DebugPrint()
    {
        for(int i=0;i<N;++i)
        {
            if(fd_arry[i].fd==defaultfd) continue;
            std::cout<<fd_arry[i].fd<<" ";
        }
    }

    ~PollServer()
    {
        listensockfd_.Close();
    }

private:
    uint16_t port_;
    Sock listensockfd_;
    FdEvent fd_arry[N]; // 存储socket套接字
};
